#!/usr/bin/env python
#!-*- coding: utf-8 -*-
#fetion_tcp.py is to send packeget by TCP
import sys
import re
import socket
import urllib2
import binascii
import hashlib

from hashlib import md5
from hashlib import sha1
from uuid import uuid1
from time import sleep

cellphone="151******0"
password="love*******"


fetionOnline="400"
fetionOffline="365"
fetionHidden="0"
fetionBusy="600"
fetionAway="100"

sipURL=""
sipProxy=""
httpTunnel=""

loginUserSSIC=""
loginUserSID=""
loginUserURI=""
loginUserStatus=""

fetionDomain = "fetion.com.cn"

nonce=""
cnonce=""
salt="777A6D03"

tcpClientSock=""
tcpChatSock=""

fetionSystemConfigURL="http://nav.fetion.com.cn/nav/getsystemconfig.aspx"
#fetionHttpHead = {'User-Agent': 'IIC2.0/PC 3.2.0540'}
fetionHttpHead = {'User-Agent': 'IIC2.0/PC 3.5.2540'}
fetionSIPP="SIPP"

#fetionConfigXML="""<config><user mobile-no="%s" /><client type="PC" version="3.2.0540" platform="W5.1" /><servers version="0" /><service-no version="0" /><parameters version="0" /><hints version="0" /><http-applications version="0" /><client-config version="0" /></config>"""
fetionConfigXML="""<config><user mobile-no="%s" /><client type="PC" version="3.5.2540" platform="W6.1" /><servers version="0" /><service-no version="0" /><parameters version="0" /><hints version="0" /><http-applications version="0" /><client-config version="0" /><services version="0" /></config>"""

#fetionLoginXML="""<args><device type="PC" version="0" client-version="3.2.0540" /><caps value="simple-im;im-session;temp-group;personal-group" /><events value="contact;permission;system-message;personal-group" /><user-info attributes="all" /><presence><basic value="400" desc="" /></presence></args>"""
fetionLoginXML="""<args><device type="PC" version="1" client-version="3.5.2540" /><caps value="simple-im;im-session;temp-group;personal-group;im-relay;xeno-im;direct-sms;sms2fetion" /><events value="contact;permission;system-message;personal-group;compact" /><user-info attributes="all" /><presence><basic value="%s" desc="" /></presence></args>"""

fetionContactListXML="""<args><contacts><buddy-lists /><buddies attributes="all" /><mobile-buddies attributes="all" /><chat-friends /><blacklist /><allow-list /></contacts></args>"""

fetionFriendStatusXML="""<args><contacts><contact uri="%s" /></contacts></args>"""
fetionFriendInfoXML="""<args><contacts attributes="all"><contact uri="%s" /></contacts></args>"""

sipRegisterGetNonceStruct="""
R %s SIP-C/2.0
F: %s
I: 1
Q: 1 R
L: %s

"""

sipRegisterStruct="""
R %s SIP-C/2.0
F: %s
I: 1
Q: 1 R
A: Digest algorithm="SHA1-sess",response="%s",cnonce="%s",salt="777A6D03",ssic="%s"
L: %s

"""

sipSendMsgStruct="""
M %s SIP-C/2.0
F: %s
I: 1
Q: 1 M
T: %s
C: text/plain
K: SaveHistory
N: CatMsg
L: %s

"""
sipGetContactListStruct="""
S %s SIP-C/2.0
F: %s
I: 1
Q: 1 S
N: GetContactList
L: %s

"""
sipGetFriendStatusStruct="""
S %s SIP-C/2.0
F: %s
I: 1
Q: 1 S
N: InviteBuddy
L: %s

"""
sipStartChatStruct="""
S %s SIP-C/2.0
F: %s
I: 1
Q: 1 S
N: StartChat

"""
sipFetionShowStruct="""
R %s SIP-C/2.0
F: %s
I: 1
Q: 1 R
A: TICKS auth="%s"
K: text/html-fragment
K: multiparty
K: nudge
K: share-background
K: fetion-show

"""
sipGetContactInfoStruct="""
S %s SIP-C/2.0
F: %s
I: 1
Q: 1 S
N: GetContactsInfo
L: %s

"""
sipCompactlistStruct="""
SUB %s SIP-C/2.0
F: %s
I: 1
Q: 1 SUB
N: compactlist
L: %s

"""
fetionCompactlistXML="""<args><subscription><contacts><contact uri="sip:949754701@fetion.com.cn;p=10098" type="3" /><contact uri="sip:903721017@fetion.com.cn;p=10098" type="3" /><contact uri="sip:858885454@fetion.com.cn;p=6067" type="3" /></contacts></subscription></args>"""

sipGetOfflineMsgStruct="""
S %s SIP-C/2.0
F: %s
I: 1
Q: 1 S
N: GetOfflineMessages

"""
sipLogoutStruct="""
R %s SIP-C/2.0
F: %s
I: 1
Q: 1 R
X: 0

"""

def tcpInit(host, port):
    """ 创建SOCKET，并连接对方ADDR
        返回socket
    """
    print host, port    
    try:
        tcpSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)     
    except socket.error,e:
        print e.read()
        sys.exit(-1)
    port = int(port)
    addr = (host, port)
    try:
        tcpSock.connect(addr)
    except socket.error,e:
        tcpSock.close()
        print e.read()

    return tcpSock

def tcpSend(tcpSocketID, data=''):    
    """发送TCP数据包
       返回数据包response
    """
    print "=====tcp_send:\n"
    print data
    try:
        tcpSocketID.send(data)
    except socket.error,e:
        tcpSocketID.close()
        print e
        sys.exit(-1)
    try:
        response = tcpSocketID.recv(4096)
        print "====tcprevc msg:"     
    except socket.error,e:
       tcpSockID.close()
       print e.read()
       sys.exit(-1)
    return response

def tcpClose(tcpSock):
    tcpSock.close()

def tcpHandle(data="", addr= '', first=False, last=False, which='NULL'):
    print len(data)
    global tcpClientSocket
    print "===tcpsend msg:\n%s" % data
    if first:
        try:
            tcpClientSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            #global tcpClientSocket2
            #if '1' == which:
            #tcpClientSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            #if '2' == which:
                #tcpClientSocket2 = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        except socket.error,e:
            print e.read()
            sys.exit(-1)

        host = sipProxy.split(":")[0]
        port = int(sipProxy.split(":")[1])
        addr = (host, port)
        try:
            tcpClientSocket.connect(addr)
        except socket.error,e:
            tcpClientSocket.close()
            print e.read()
            sys.exit(-1)
    try:
        tcpClientSocket.send(data)
    except socket.error,e:
        tcpClientSocket.close()
        print e.read()
        sys.exit(-1)

    try:
        response = tcpClientSocket.recv(4096)
        print "====tcprevc msg:"
     
    except socket.error,e:
       tcpClientSocket.close()
       print e.read()
       sys.exit(-1)
    if last:
        tcpClientSocket.close()
        tcpClientSocket=''
    return response


def getFetionSystemConfig():
    body = fetionConfigXML%(cellphone)
    print body
    print len(body)
    request = urllib2.Request(fetionSystemConfigURL, data=body, headers=fetionHttpHead)
    conn = urllib2.urlopen(request)
    header = str(conn.info())
    body   = conn.read()
    print header
    #print body
    global sipURL
    global sipProxy
    global httpTunnel
    sipURL = re.search("<ssi-app-sign-in>(.*)</ssi-app-sign-in>",body).group(1)
    sipProxy = re.search("<sipc-proxy>(.*)</sipc-proxy>",body).group(1)
    httpTunnel = re.search("<http-tunnel>(.*)</http-tunnel>",body).group(1)
    print "=========sipurl proxy httptunnel got==========="
    print sipURL, sipProxy, httpTunnel

def getLoginUserInfo(cellphone, password):
    url = sipURL+"?mobileno="+cellphone+"&pwd="+password
    req = urllib2.Request(url, headers=fetionHttpHead)
    response = urllib2.urlopen(req)
    header = str(response.info())
    body   = response.read()
    print header
    print body
    global loginUserSSIC
    global loginUserSID
    global loginUserURI
    global loginUserStatus
    loginUserSSIC = re.search("ssic=(.*);",header).group(1)
    loginUserSID  = re.search("sip:(.*)@",body).group(1)
    loginUserURI  = re.search('uri="(.*)" mobile-no',body).group(1)
    loginUserStatus = re.search('user-status="(\d+)"',body).group(1)
    print "=========ssic sid uri status==========="
    print loginUserSSIC, loginUserSID, loginUserURI, loginUserStatus

def getSIPCnonce():
    fetionLoginXMLFormat = fetionLoginXML % fetionOnline
    sipRegFormat = sipRegisterGetNonceStruct % (fetionDomain,loginUserSID,len(fetionLoginXMLFormat))
    
    print "======tou======1"
    print len(sipRegFormat)
    data = sipRegFormat+fetionLoginXMLFormat
    print data

    host = sipProxy.split(":")[0]
    port = int(sipProxy.split(":")[1])
    global tcpClientSock
    tcpClientSock = tcpInit(host, port)
    reciveMessage = tcpSend(tcpSocketID=tcpClientSock, data=data)
    #reciveMessage = tcpHandle(data, first=True, last=False)
    print reciveMessage
    global nonce
    nonce = re.search('nonce="(.*)"',reciveMessage).group(1)
    print nonce

def setResponse():
    global cnonce
    global response
    
    cnonce = md5(str(uuid1())).hexdigest().upper()
    salt = 'wzm\x03'
    src  = salt+sha1(password).digest()
    hash_passwd = "777A6D03"+sha1(src).hexdigest().upper()
    hash_passwd_str = binascii.unhexlify(hash_passwd[8:])
    key = sha1("%s:%s:%s" % (loginUserSID,fetionDomain,hash_passwd_str)).digest()
    h1  = md5("%s:%s:%s" % (key,nonce,cnonce)).hexdigest().upper()
    h2  = md5("REGISTER:%s" % loginUserSID).hexdigest().upper()
    response = md5("%s:%s:%s" % (h1,nonce,h2)).hexdigest().upper()
    salt = "777A6D03"+sha1(src).hexdigest().upper()[:8]
    print response

def sipRegister():
    fetionLoginXMLFormat = fetionLoginXML % fetionOnline
    sipRegFormat = sipRegisterStruct % (fetionDomain, loginUserSID, response, cnonce, loginUserSSIC, len(fetionLoginXMLFormat))
    print "======tou======"
    print len(sipRegFormat)
    data = sipRegFormat+fetionLoginXMLFormat
    reciveMessage = tcpSend(tcpSocketID=tcpClientSock, data=data)
    #reciveMessage = tcpSend(data, first=False, last=False)
    print reciveMessage

def sipSendMessage(message="", to=""):
    sipSendMsgStructFormat = sipSendMsgStruct % (fetionDomain, loginUserSID, "sip:858885454@fetion.com.cn;p=6067", len(message))
    data = sipSendMsgStructFormat+message
    reciveMessage = tcpSend(tcpSocketID=tcpClientSock, data=data)
    #reciveMessage = tcpSend(data, first=False, last=False)
    print reciveMessage

def sipGetContactList():
    sipGetContactListStructFormat = sipGetContactListStruct % (fetionDomain, loginUserSID, len(fetionContactListXML))
    data = sipGetContactListStructFormat+fetionContactListXML
    reciveMessage = tcpSend(tcpSocketID=tcpClientSock, data=data)
    #reciveMessage = tcpSend(data, first=False, last=False)
    print reciveMessage

def sipGetFriendStatus(friendSID):
    
    sipStartChatStructFormat = sipStartChatStruct % (fetionDomain, loginUserSID)
    data = sipStartChatStructFormat
    
    #reciveMessage = tcpSend(data, first=False, last=True)
    reciveMessage = tcpSend(tcpSocketID=tcpClientSock, data=data)
    print reciveMessage
    #tcpClose(tcpClientSock)
    #credential = re.search('credential="(.*)"',reciveMessage).group(1)
    #cs_address = re.search('address="(.*);',reciveMessage).group[1]
    credential = re.findall('credential="(.+?)"',reciveMessage)[0]
    cs_address = re.findall('address="(.+?);',reciveMessage)[0]
    print credential, cs_address

    sipFetionShowStructFormat = sipFetionShowStruct % (fetionDomain, loginUserSID, credential)
    data = sipFetionShowStructFormat

    host = cs_address.split(":")[0]
    port = cs_address.split(":")[1]
    global tcpChatSock
    tcpChatSock = tcpInit(host, port)
    reciveMessage = tcpSend(tcpSocketID=tcpChatSock, data=data)
    #reciveMessage = tcpSend(data, first=True, last=False)
    print reciveMessage

    fetionFriendStatusXMLFormat = fetionFriendStatusXML % friendSID
    print fetionFriendStatusXMLFormat, len(fetionFriendStatusXMLFormat)
    sipGetFriendStatusStructFormat = sipGetFriendStatusStruct % (fetionDomain, loginUserSID, len(fetionFriendStatusXMLFormat))
    data = sipGetFriendStatusStructFormat+fetionFriendStatusXMLFormat
    print data
    reciveMessage = tcpSend(tcpSocketID=tcpChatSock, data=data)
    #reciveMessage = tcpSend(data, first=False, last=False)
    print reciveMessage
    msg = tcpChatSock.recv(1024)
    print msg
    status = re.findall('<event type="(.+?)">',msg)[0]
    print status
    if "UserFailed" == status:
        print "好友不在线!"
    if "UserEntered" == status:
        print "好友在线或者隐身"

def sipGetFriendInfo(friendSID):
    fetionFriendInfoXMLFormat = fetionFriendInfoXML % friendSID
    sipGetContactInfoStructFormat = sipGetContactInfoStruct % (fetionDomain, loginUserSID, len(fetionFriendInfoXMLFormat))
    data = sipGetContactInfoStructFormat+fetionFriendInfoXMLFormat
    reciveMessage = tcpSend(tcpSocketID=tcpClientSock, data=data)
    #reciveMessage = tcpSend(data, first=False, last=False)
    print reciveMessage

def sipCompactlist():
    sipCompactlistStructFormat = sipCompactlistStruct % (fetionDomain, loginUserSID, len(fetionCompactlistXML))
    data = sipCompactlistStructFormat+fetionCompactlistXML
    print data
    reciveMessage = tcpSend(tcpSocketID=tcpClientSock, data=data)
    #reciveMessage = tcpSend(data, first=False, last=False)
    print reciveMessage

def sipGetOfflineMsg():
    sipGetOfflineMsgStructFormat = sipGetOfflineMsgStruct % (fetionDomain, loginUserSID)
    data = sipGetOfflineMsgStructFormat
    reciveMessage = tcpSend(tcpSocketID=tcpClientSock, data=data)
    #reciveMessage = tcpSend(data, first=False, last=False)
    print reciveMessage

def sipLogout():
    sipLogoutStructFormat = sipLogoutStruct % (fetionDomain, loginUserSID)
    data = sipLogoutStructFormat
    reciveMessage = tcpSend(tcpSocketID=tcpClientSock, data=data)
    #reciveMessage = tcpSend(data, first=False, last=True)
    print reciveMessage


def main():
    getFetionSystemConfig()
    getLoginUserInfo(cellphone, password)
    getSIPCnonce()
    setResponse()
    sipRegister()
    #sleep(10)
    sipSendMessage("hi..")
    #sipGetContactList()
    #sipGetFriendInfo("sip:903721017@fetion.com.cn;p=10098")
    #sipCompactlist() ##sipRegister后，经过sipCompactlist飞信就会显示登录成功。
    #sleep(10)
    #sipGetOfflineMsg()
    #sipGetFriendStatus("sip:858885454@fetion.com.cn;p=6067")

    #sipLogout()
    tcpClose(tcpChatSock)
    sleep(5)
    #tcpClientSocket.close()
    

if __name__ == "__main__":
    sys.exit(main())
